/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "数据缓存.h"
#include "节点/插座/通用插座.h"
#include "节点/插座/list/list数值插座.h"
#include "节点/插座/list/list矢量插座.h"
#include "节点/插座/list/list物体插座.h"
#include "节点/插座/list/list物理物体插座.h"
#include "节点/socket_utils.h"
#include "Context/数据创建销毁.h"

#include <场景/intern/S_Scene.h>




std::filesystem::path f_缓存文件路径生成(S_Props& m_Path, std::u16string name, bool 序列, int32 帧编号, const std::u16string& 后缀) {
	auto path = f_prop_Path(m_Path).string();
	std::string 拼接路径 = f_nodeCtx_相对路径补全(path);
	if(拼接路径.empty()) return "";

	if (f_file_文件是否存在(拼接路径) == false) {
		f_file_创建目录(拼接路径);
	}

	auto 帧 = f_整数值转字符串(帧编号);
	std::filesystem::path 路径 = 拼接路径;
	name += 后缀;

	return 路径 / name;
}
static S_Props f_网格元素位域属性创建() {
	auto 元素 = f_alloc_bool_1DProp(8, u"缓存位域");
	元素.m_私有 = true;
	S_PropVecBool* 元素开关 = f_prop_Bool_1D(元素);
	元素开关[0].m_Names = L"顶点"; 元素开关[0].m_ICO = "三角顶点"; 元素开关[0].m_Value = true;
	元素开关[1].m_Names = L"法线"; 元素开关[1].m_ICO = "平面法线"; 元素开关[1].m_Value = true;
	元素开关[2].m_Names = L"UV"; 元素开关[2].m_ICO = "材质"; 元素开关[2].m_Value = false;
	元素开关[3].m_Names = L"索引"; 元素开关[3].m_ICO = "指示ID"; 元素开关[3].m_Value = false;
	元素开关[4].m_Names = L"材质ID"; 元素开关[4].m_ICO = "材质ID"; 元素开关[4].m_Value = false;
	元素开关[5].m_Names = L"面平滑"; 元素开关[5].m_ICO = "曲线顶点"; 元素开关[5].m_Value = false;
	元素开关[6].m_Names = L"顶点颜色"; 元素开关[6].m_ICO = "球"; 元素开关[6].m_Value = false;
	元素开关[7].m_Names = L"顶点颜色"; 元素开关[7].m_ICO = "球"; 元素开关[7].m_Value = false;
	return 元素;
}
static uint32 f_网格元素位域(const S_Props& 元素) {
	const S_PropVecBool* 元素开关 = f_prop_Bool_1D(元素);
	uint32 网格元素 = 0;
	if (元素开关[0].m_Value) 网格元素 |= uint32(E_网格缓存元素位域::e_顶点坐标);
	if (元素开关[1].m_Value) 网格元素 |= uint32(E_网格缓存元素位域::e_顶点法线);
	if (元素开关[2].m_Value) 网格元素 |= uint32(E_网格缓存元素位域::e_顶点UV);
	if (元素开关[3].m_Value) 网格元素 |= uint32(E_网格缓存元素位域::e_顶点索引);
	if (元素开关[6].m_Value) 网格元素 |= uint32(E_网格缓存元素位域::e_顶点颜色);
	return 网格元素;
}


C_数据缓存写入节点::C_数据缓存写入节点(S_设备环境& ctx) : C_节点基类(DEF_数据缓存写入节点, E_节点类型::e_节点Type_文件) {
	f_setWName(u"数据缓存写入");

	C_插座基类* socket;
	DEF_创建引用插座_I(u"源");
	DEF_创建UI32插座_I(u"帧");

	m_Path = f_alloc_PathProp(nullptr, u"保存路径");
	m_Path.m_私有 = true;

	m_文件名 = f_alloc_LineStrProp(nullptr, u"文件名");
	m_文件名.m_私有 = true;

	m_格式 = f_alloc_EnumProp(nullptr, { 
		{u"auto",	u""},
		{u"geom",	u""},
		{u"vdb",	u""}, 
		{u"PBF",	u""} 
	}, u"格式");
	m_格式.m_私有 = true;

	m_压缩 = f_alloc_BoolProp(nullptr, u"压缩");
	m_压缩.m_私有 = true;
	f_prop_Bool(m_压缩) = false;

	m_覆盖文件 = f_alloc_BoolProp(nullptr, u"覆盖文件");
	m_覆盖文件.m_私有 = true;
	f_prop_Bool(m_覆盖文件) = true;

	m_序列 = f_alloc_BoolProp(nullptr, u"序列");
	m_序列.m_私有 = true;
	f_prop_Bool(m_序列) = false;


	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;
	m_自定义更新方式 = true;
}

C_数据缓存写入节点::~C_数据缓存写入节点() {
	f_prop_Release(m_Path);
	f_prop_Release(m_格式);
	f_prop_Release(m_文件名);
	f_prop_Release(m_压缩);
	f_prop_Release(m_覆盖文件);
	f_prop_Release(m_序列);
}

bool C_数据缓存写入节点::f_update() {
	f_su_插座类型切换到连入的插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Array);
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	if (f_更新是否跳过()) {
		return false;
	}

	int32 帧编号 = DEF_I32插座数据(socket2);
	if (f_prop_Bool(m_序列)) {
		if (socket2->f_isLink() == false) {
			帧编号 = f_NodeCtx_get帧().当前帧;
		}
		//m_更新方式 = E_节点更新方式::e_节点更新_逐帧;
	}
	else {
		//m_更新方式 = E_节点更新方式::e_节点更新_被动;
	}
	auto name = f_prop_LineStr(m_文件名);
	auto 文件名 = f_缓存文件路径生成(m_Path, name, f_prop_Bool(m_序列), 帧编号, u".array");

	


	FILE* f;
	f = fopen(文件名.generic_string().c_str(), "wb");
	if (f) {
		auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_数组缓存, S_引擎配置::g_文件版本号);
		S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));


		uint32 type = socket1->m_Type;
		f_文件块_写数据块(块, type);
		f_文件块_写数据块(块, f_prop_Bool(m_压缩));
		switch (type) {
			case E_值类型::e_Type_Bool_1D:
			case E_值类型::e_Type_F32_1D:
			case E_值类型::e_Type_I8_1D:
			case E_值类型::e_Type_I32_1D:
			case E_值类型::e_Type_UI32_1D:
			case E_值类型::e_Type_Vec2_1D:
			case E_值类型::e_Type_Vec3_1D: 
			case E_值类型::e_Type_Vec4_1D: {
				auto data = socket1->f_getData(0);
				f_文件块_写序列数据块(块, (S_Array*)data, f_prop_Bool(m_压缩));
				break;
			}

			case E_值类型::e_Type_UI32_2D: {
				auto* data = DEF_UI32插座_2D数据(socket1);
				std::vector<uint32> 元素数量(data->count);
				std::vector<uint32> 元素序列;

				for (uint32 i = 0; i < data->count; ++i) {
					S_UI32Array* 元素 = data->ptr_userData[i];
					uint32 数量 = 元素->count;
					元素数量[i] = 数量;

					for (uint32 k = 0; k < 数量; ++k) {
						元素序列.push_back(元素->ptr_userData[k]);
					}
				}

				f_文件块_写序列数据块(块, 元素数量, f_prop_Bool(m_压缩));
				f_文件块_写序列数据块(块, 元素序列, f_prop_Bool(m_压缩));
				break;
			}
			
			default:
				break;
		}
		f_file_保存文件块(f, 文件块, 块);
		fclose(f);
	}

	return false;
}

void C_数据缓存写入节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件名, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_格式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_压缩, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_覆盖文件, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_序列, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_数据缓存写入节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_Path, 块);
	f_prop_Save(m_文件名, 块);
	f_prop_Save(m_格式, 块);
	f_prop_Save(m_压缩, 块);
	f_prop_Save(m_覆盖文件, 块);
	f_prop_Save(m_序列, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建写入数据缓存节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_数据缓存写入节点(ctx);
}

C_节点基类* f_node_加载写入数据缓存节点(S_设备环境& ctx, FILE* f) {
	C_数据缓存写入节点* node = new C_数据缓存写入节点(ctx);
	return node;
}

void f_node_保存写入数据缓存节点(C_节点基类* n, FILE* f) {
	C_数据缓存写入节点* node = dynamic_cast<C_数据缓存写入节点*>(n);
}












C_数据缓存读取节点::C_数据缓存读取节点(S_设备环境& ctx) : C_节点基类(DEF_数据缓存读取节点, E_节点类型::e_节点Type_文件) {
	f_setWName(u"数据缓存读取");
	m_Ctx = ctx;
	m_自定义更新方式 = true;

	C_插座基类* socket;
	DEF_创建UI32插座_I(u"帧");
	DEF_通用数据插座创建_O(u"数据");


	m_Path = f_alloc_PathProp(nullptr, u"保存路径");
	m_Path.m_私有 = true;

	m_格式 = f_alloc_EnumProp(nullptr, { {u"geom", u""}, {u"vdb", u""}, {u"PBF", u""} }, u"格式");
	m_格式.m_私有 = true;

	m_文件名 = f_alloc_LineStrProp(nullptr, u"文件名");
	m_文件名.m_私有 = true;

	m_序列 = f_alloc_BoolProp(nullptr, u"序列");
	m_序列.m_私有 = true;
	f_prop_Bool(m_序列) = false;

	m_开启预载 = f_alloc_BoolProp(nullptr, u"序列");
	m_开启预载.m_私有 = true;
	f_prop_Bool(m_开启预载) = false;

	m_预载区间 = f_alloc_iVec2Prop(nullptr, u"序列");
	m_预载区间.m_私有 = true;
	f_prop_iVec2(m_预载区间) = {0,0};

}

C_数据缓存读取节点::~C_数据缓存读取节点() {
	f_prop_Release(m_Path);
	f_prop_Release(m_格式);
	f_prop_Release(m_文件名);
	f_prop_Release(m_序列);
	f_prop_Release(m_开启预载);
	f_prop_Release(m_预载区间);
}

bool C_数据缓存读取节点::f_update() {
	if (f_更新是否跳过()) {
		return false;
	}

	auto* socket1 = f_get输入插座(1);
	int32 帧编号 = DEF_I32插座数据(socket1);
	if (f_prop_Bool(m_序列)) {
		if (socket1->f_isLink() == false) {
			帧编号 = f_NodeCtx_get帧().当前帧;
		}
		//m_更新方式 = E_节点更新方式::e_节点更新_逐帧;
	}
	else {
		//m_更新方式 = E_节点更新方式::e_节点更新_被动;
	}
	auto name = f_prop_LineStr(m_文件名);
	auto 文件名 = f_缓存文件路径生成(m_Path, name, f_prop_Bool(m_序列), 帧编号, u".array");


	if (f_prop_Bool(m_开启预载)) {

	}
	else {

	}

	FILE* f;
	f = fopen(文件名.generic_string().c_str(), "rb");
	if (f) {
		S_文件块 文件块 = f_file_读取文件块(f);
		if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_数组缓存) {
			const uint8* 下一次读取数据指针 = 文件块.m_data;
			uint32 type = 0;
			bool 压缩 = false;
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, type);
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, 压缩);

			E_值类型 outType = E_值类型(type);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, outType);
			S_Array* outData = (S_Array*)f_get输出插座(1)->f_getData(0);

			
			switch (outType) {
				case E_值类型::e_Type_Bool_1D:
				case E_值类型::e_Type_F32_1D:
				case E_值类型::e_Type_I8_1D:
				case E_值类型::e_Type_I32_1D:
				case E_值类型::e_Type_UI32_1D:
				case E_值类型::e_Type_Vec2_1D:
				case E_值类型::e_Type_Vec3_1D:
				case E_值类型::e_Type_Vec4_1D: {
					下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, outData, 压缩);
					break;
				}
				case E_值类型::e_Type_UI32_2D: {
					auto* data = DEF_UI32插座_2D数据(f_get输出插座(1));
					std::vector<uint32> 元素数量;
					std::vector<uint32> 元素序列;
					下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, 元素数量, 压缩);
					下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, 元素序列, 压缩);

					f_core_array_resize((S_Array*)data, 元素数量.size());
//#pragma omp parallel for num_threads(DEF_Min(8, data->count))
					uint64 offset = 0;
					for (int64 i = 0; i < data->count; ++i) {
						uint32 数量 = 元素数量[i];
						
						S_UI32Array* 元素 = (S_UI32Array*)f_core_array_new_type(数量, E_值类型::e_Type_UI32_1D);
						for (uint32 k = 0; k < 数量; ++k) {
							元素->ptr_userData[k] = 元素序列[offset + k];
						}
						f_core_array_CleanUnusedMemory((S_Array*)元素);
						data->ptr_userData[i] = 元素;
						offset += 数量;
					}

					f_core_array_CleanUnusedMemory((S_Array*)data);
					break;
				}
				default:
					break;
			}
		}
		fclose(f);
	}

	return false;
}

void C_数据缓存读取节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_14, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_格式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件名, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_序列, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_开启预载, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_预载区间, 下一次读取数据指针);
		}
		else if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_格式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件名, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_序列, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_数据缓存读取节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_Path, 块);
	f_prop_Save(m_格式, 块);
	f_prop_Save(m_文件名, 块);
	f_prop_Save(m_序列, 块);
	f_prop_Save(m_开启预载, 块);
	f_prop_Save(m_预载区间, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建数据缓存读取节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_数据缓存读取节点(ctx);
}

C_节点基类* f_node_加载数据缓存读取节点(S_设备环境& ctx, FILE* f) {
	C_数据缓存读取节点* node = new C_数据缓存读取节点(ctx);
	return node;
}

void f_node_保存数据缓存读取节点(C_节点基类* n, FILE* f) {
	C_数据缓存读取节点* node = dynamic_cast<C_数据缓存读取节点*>(n);
}






C_物体缓存节点::C_物体缓存节点(S_设备环境& ctx) : C_节点基类(DEF_物体缓存节点) {
	f_setWName(u"物体缓存");
	m_Ctx = ctx;
	m_自定义更新方式 = true;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建物体_1D插座_O(u"物体");

	m_Path = f_alloc_PathProp(nullptr, u"文件路径");
	m_Path.m_私有 = true;

	m_类型 = f_alloc_EnumProp(nullptr, {
	    {u"物体",	u""},
		{u"多边形",	u""},
		{u"网格",	u""},
		
		{u"网格自定义属性",	u""},
	}, u"缓存类型");
	m_类型.m_私有 = true;

	m_应用变换 = f_alloc_BoolProp(nullptr, u"应用变换");
	m_应用变换.m_私有 = true;
	f_prop_Bool(m_应用变换) = false;

	m_中心变换方式 = f_alloc_EnumProp(nullptr, {
		{u"保存偏移",	u""},
		{u"世界原点",	u""},
		{u"原物体",		u""},
		}, u"中心变换");
	m_中心变换方式.m_私有 = true;
	f_prop_enum(m_中心变换方式) = 0;


	m_实时写入 = f_alloc_BoolProp(nullptr, u"实时写入");
	m_实时写入.m_私有 = true;
	f_prop_Bool(m_实时写入) = false;

	m_压缩 = f_alloc_BoolProp(nullptr, u"压缩");
	m_压缩.m_私有 = true;
	f_prop_Bool(m_压缩) = false;

	m_复制 = f_alloc_BoolProp(nullptr, u"复制物体");
	m_复制.m_私有 = true;
	f_prop_Bool(m_复制) = false;

	m_多线程 = f_alloc_BoolProp(nullptr, u"多线程");
	m_多线程.m_私有 = true;
	f_prop_Bool(m_多线程) = false;


	m_上一次加载路径 = std::filesystem::temp_directory_path().string();

	m_拷贝物体组 = (S_OBArray*)f_core_array_new(0, sizeof(S_物体*));

	m_自定义更新方式 = true;
	m_开启缓存节点 = false;
}

C_物体缓存节点::~C_物体缓存节点() {
	f_prop_Release(m_Path);
	f_prop_Release(m_类型);
	f_prop_Release(m_应用变换);
	f_prop_Release(m_中心变换方式);
	f_prop_Release(m_实时写入);
	f_prop_Release(m_复制);
	f_prop_Release(m_多线程);

	f_core_array_free((S_Array*)m_拷贝物体组);
}

bool C_物体缓存节点::f_update() {
	if (f_更新是否跳过()) {
		return false;
	}

	
	auto socket1 = f_get输入插座(1);

	auto 路径 = f_prop_Path(m_Path).string();
	std::string 拼接路径 = f_nodeCtx_相对路径补全(路径);


	auto* InObjs = DEF_物体插座_1D数据(socket1, 0);
	if ((m_更新方式 & E_节点更新方式::e_节点更新_手动) && S_节点数据::g_开启节点手动更新 == false) {
		f_get输出插座(1)->f_setData(InObjs);
		return false;
	}

	bool 跳过 = (m_更新方式 & E_节点更新方式::e_节点更新_关闭);
	if (((m_更新方式 & E_节点更新方式::e_节点更新_离线) && !S_节点数据::g_开启离线更新) || 跳过) {
		f_get输出插座(1)->f_setData(InObjs);
		return false;
	}
	

	if (m_冻结数据 || socket1->f_isLink() == false) {
		if(m_上一次加载路径 == 拼接路径) return false;
		if (m_上一次加载路径 != 拼接路径) {
			m_上一次加载路径 = 拼接路径;

			for (uint32 i = 0; i < m_拷贝物体组->count; ++i) {
				f_node_物体从主场景中移除(m_拷贝物体组->ptr_userData[i]);
				f_node_从全局容器移除物体(m_拷贝物体组->ptr_userData[i]);
			}
			f_node_删除物体(m_拷贝物体组);

			if(f_file_文件是否存在(m_上一次加载路径) == false) return false;

			FILE* f = fopen(拼接路径.c_str(), "rb");
			if (f) {
				uint32 物体数量 = 0;

				{
					S_文件块 文件块 = f_file_读取文件块(f);
					if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_模型物体) {
						const uint8* 下一次读取数据指针 = 文件块.m_data;
						if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
							下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, 物体数量);
						}
					}
					free(文件块.m_data);
				}
				


				std::vector<S_文件块> 文件块组;
				f_core_array_resize((S_Array*)m_拷贝物体组, 物体数量);

				for (uint32 i = 0; i < 物体数量; ++i) {
					文件块组.push_back(f_file_读取文件块(f));
				}

				std::atomic_uint 完成数量 = 0;
			//#pragma omp parallel for
				for (int32 i = 0; i < 物体数量; ++i) {
					auto& 块 = 文件块组[i];

					if (块.m_块类型 == E_节点工程文件块类型::e_工程文件块_模型物体) {
						const uint8* 下一次读取数据指针 = 块.m_data;

						if (f_file_版本对比(块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
							下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, f_prop_Bool(m_压缩));
							下一次读取数据指针 = f_ob_Load模型(&(m_拷贝物体组->ptr_userData[i]), 下一次读取数据指针, m_Ctx, true, f_node_构建物体模型);
						}

						std::cout<<"载入模型:"<< 物体数量<<"/"<< ++完成数量 << std::endl;
					}
					else {
						m_拷贝物体组->ptr_userData[i] = nullptr;
					}

					free(块.m_data);
				}

				fclose(f);
			}


			for (uint32 i=0; i< m_拷贝物体组->count; ++i) {
				auto* ob = m_拷贝物体组->ptr_userData[i];

				switch (ob->m_Type) {
					case E_物体类型::t_多边形: {
						S_Mesh* 轮廓 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_焦点);
						S_Mesh* 面网格 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_面);
						S_Mesh* 点网格 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_点);
						S_Mesh* 边网格 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_边);
						f_surface_多边形转网格((S_多边形*)ob->m_UserData, 面网格, 点网格, 边网格, true);

						f_mesh_计算包围盒(面网格);
						break;
					}
					case E_物体类型::t_网格物体: {
						break;
					}
					default:
						continue;
				}

				f_node_物体添加到全局容器(ob);
			}

			uint32 num = DEF_Min(m_变换组.size(), m_拷贝物体组->count);
			f_get输出插座(1)->m_有新数据 = true;
			for (uint32 i = 0; i < num; ++i) {
				m_拷贝物体组->ptr_userData[i]->m_变换 = m_变换组[i];
			}
			m_变换组.clear();

			f_node_物体添加到主场景(m_拷贝物体组);
			

			f_get输出插座(1)->f_setData(m_拷贝物体组);
		}
	}
	else {
		
		f_node_删除物体(m_拷贝物体组);
		
		if (InObjs->count) {
			auto 路径 = 拼接路径;
			

			FILE* f = fopen(路径.c_str(), "wb");
			if (f) {
				m_上一次加载路径 = 路径;

				E_物体类型 保存指定类型;
				switch (f_prop_enum(m_类型)) {
					case 0:
					case 1: {
						保存指定类型 = E_物体类型::t_多边形;
						break;
					}
					case 2: {
						保存指定类型 = E_物体类型::t_网格物体;
						break;
					}
					default:
						保存指定类型 = E_物体类型::t_空;
						break;
				}


				{
					auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_模型物体, S_引擎配置::g_文件版本号);
					S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
					f_文件块_写数据块(块, (uint32)InObjs->count);
					f_file_保存文件块(f, 文件块, 块);
				}
				

				std::vector<S_文件块> 文件块组(InObjs->count);
				std::vector<S_UI8Array*> 块组(InObjs->count);
				if (f_prop_Bool(m_多线程)) {

					static std::mutex g容器添加锁;

#pragma omp parallel for num_threads(DEF_Min(8, InObjs->count))
					for (int32 i = 0; i < InObjs->count; ++i) {
						auto 模型文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_模型物体, S_引擎配置::g_文件版本号);
						S_UI8Array* 模型数据块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

						f_文件块_写数据块(模型数据块, f_prop_Bool(m_压缩));
						f_ob_Save模型(InObjs->ptr_userData[i], 模型数据块, true, 保存指定类型);
						
						//g容器添加锁.lock();
						文件块组[i] = (模型文件块);
						块组[i] = (模型数据块);
						//g容器添加锁.unlock();
					}
				}
				else {
					for (int32 i = 0; i < InObjs->count; ++i) {
						auto 模型文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_模型物体, S_引擎配置::g_文件版本号);
						S_UI8Array* 模型数据块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

						f_文件块_写数据块(模型数据块, f_prop_Bool(m_压缩));
						f_ob_Save模型(InObjs->ptr_userData[i], 模型数据块, true, 保存指定类型);

						文件块组[i] = (模型文件块);
						块组[i] = (模型数据块);
					}
				}

				for (int32 i = 0; i < InObjs->count; ++i) {
					f_file_保存文件块(f, 文件块组[i], 块组[i]);
				}
				fclose(f);



				if (f_prop_Bool(m_复制)) {
					f_core_array_resize((S_Array*)m_拷贝物体组, InObjs->count);

					for (uint32 i = 0; i < InObjs->count; ++i) {
						m_拷贝物体组->ptr_userData[i] = f_ob_copy(m_Ctx, InObjs->ptr_userData[i], false);
						f_TranformInit(m_拷贝物体组->ptr_userData[i]->m_变换);
						f_ob_set矩阵(m_拷贝物体组->ptr_userData[i], f_mat44_identity());
					}

					 
					for (uint32 i = 0; i < m_拷贝物体组->count; ++i) {
						auto* ob = m_拷贝物体组->ptr_userData[i];

						switch (m_拷贝物体组->ptr_userData[i]->m_Type) {
							case E_物体类型::t_多边形: {
								f_node_构建多边形网格对象(m_拷贝物体组->ptr_userData[i], m_Ctx);

								S_Mesh* 轮廓 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_焦点);
								S_Mesh* 面网格 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_面);
								S_Mesh* 点网格 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_点);
								S_Mesh* 边网格 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_边);

								f_surface_多边形转网格((S_多边形*)ob->m_UserData, 面网格, 点网格, 边网格, true);

								if (f_prop_Bool(m_应用变换)) {
									auto mat = f_mat44_构建XYZ变换矩阵(ob->m_变换);

									f_surface_应用变换(面网格, mat);
									f_surface_应用变换(点网格, mat);
									f_surface_应用变换(边网格, mat);
								}

								f_mesh_计算包围盒(轮廓);
								break;
							}
							case E_物体类型::t_网格物体: {
								break;
							}
						}
					}
					f_node_物体添加到主场景(m_拷贝物体组);
					f_get输出插座(1)->f_setData(m_拷贝物体组);
				}
			}
		}

		f_get输出插座(1)->f_setData(InObjs);
	}

	return false;
}

void C_物体缓存节点::f_释放缓存() {
	m_上一次加载路径 = "";
}

void C_物体缓存节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		
		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_类型, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_应用变换, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_中心变换方式, 下一次读取数据指针);

			m_变换组.clear();
			下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, m_变换组, false);
		}

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_复制, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_压缩, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_多线程, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_物体缓存节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_Path, 块);
	f_prop_Save(m_类型, 块);
	f_prop_Save(m_应用变换, 块);
	f_prop_Save(m_中心变换方式, 块);

	{
		auto* OutObjs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
		m_变换组.clear();
		for (uint32 i = 0; i < OutObjs->count; ++i) {
			m_变换组.push_back(OutObjs->ptr_userData[i]->m_变换);
		}
		f_文件块_写序列数据块(块, m_变换组, false);
	}
	
	f_prop_Save(m_复制, 块);
	f_prop_Save(m_压缩, 块);
	f_prop_Save(m_多线程, 块);

	f_file_保存文件块(f, 文件块, 块);
}

S_物体* C_物体缓存节点::f_虚拟体() {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	for (uint32 i = 0; i < objs->count; ++i) {
		if(!objs->ptr_userData[i]) continue;

		switch (objs->ptr_userData[i]->m_Type) {
		case E_物体类型::t_多边形:
		case E_物体类型::t_网格物体: {
			return objs->ptr_userData[i];
		}
		}
	}
	return nullptr;
}

void C_物体缓存节点::f_删除() {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_node_物体添加到主场景(objs);
}

void C_物体缓存节点::f_回收() {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_node_物体从主场景中移除(objs);
}

void C_物体缓存节点::f_Show(bool open) {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	for (uint32 i = 0; i < objs->count; ++i) {
		objs->ptr_userData[i]->m_显示 = open;
	}
}

C_节点基类* f_node_创建物体缓存节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体缓存节点(ctx);
}

C_节点基类* f_node_加载物体缓存节点(S_设备环境& ctx, FILE* f) {
	C_物体缓存节点* node = new C_物体缓存节点(ctx);
	return node;
}

void f_node_保存物体缓存节点(C_节点基类* n, FILE* f) {
	C_物体缓存节点* node = dynamic_cast<C_物体缓存节点*>(n);
}










C_网格缓存写入节点::C_网格缓存写入节点(S_设备环境& ctx) : C_节点基类(DEF_网格缓存写入节点) {
	f_setWName(u"网格缓存写入");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建I32插座_I(u"帧");
	//DEF_创建物体_1D插座_O(L"物体");

	m_Path = f_alloc_PathProp(nullptr, u"文件路径");
	m_Path.m_私有 = true;

	m_文件名称 = f_alloc_LineStrProp(nullptr, u"文件名称");
	m_文件名称.m_私有 = true;

	m_使用物体名称 = f_alloc_BoolProp(nullptr, u"使用物体名称", false);
	m_使用物体名称.m_私有 = true;

	m_覆盖文件 = f_alloc_BoolProp(nullptr, u"覆盖文件");
	m_覆盖文件.m_私有 = true;
	f_prop_Bool(m_覆盖文件) = true;

	m_序列文件 = f_alloc_BoolProp(nullptr, u"序列文件");
	m_序列文件.m_私有 = true;
	f_prop_Bool(m_序列文件) = false;

	m_元素 = f_网格元素位域属性创建();
	

	m_应用变换 = f_alloc_BoolProp(nullptr, u"应用变换");
	m_应用变换.m_私有 = true;
	f_prop_Bool(m_应用变换) = false;

	m_中心变换方式 = f_alloc_EnumProp(nullptr, {
		{u"保存偏移",	u""},
		{u"世界原点",	u""},
		{u"原物体",		u""},
		}, u"中心变换");
	m_中心变换方式.m_私有 = true;
	f_prop_enum(m_中心变换方式) = 0;

	m_压缩 = f_alloc_BoolProp(nullptr, u"压缩");
	m_压缩.m_私有 = true;
	f_prop_Bool(m_压缩) = false;

	m_压缩等级 = f_alloc_I32Prop(nullptr, u"压缩等级");
	m_压缩等级.m_私有 = true;
	f_prop_I32(m_压缩等级) = 1;

	m_实时写入 = f_alloc_BoolProp(nullptr, u"实时写入");
	m_实时写入.m_私有 = true;
	f_prop_Bool(m_实时写入) = false;

	m_上一次加载路径 = std::filesystem::temp_directory_path().string();
	f_prop_LineStr(m_文件名称) = f_getWName();
	m_自定义更新方式 = true;
}

C_网格缓存写入节点::~C_网格缓存写入节点() {
	f_prop_Release(m_Path);
	f_prop_Release(m_文件名称);
	f_prop_Release(m_使用物体名称);
	f_prop_Release(m_覆盖文件);
	f_prop_Release(m_序列文件);
	f_prop_Release(m_元素);
	f_prop_Release(m_应用变换);
	f_prop_Release(m_中心变换方式);
	f_prop_Release(m_压缩);
	f_prop_Release(m_压缩等级);
	f_prop_Release(m_实时写入);
}

bool C_网格缓存写入节点::f_update() {
	if(f_更新是否跳过()) return false;
	//auto* OutObjs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	auto path = f_prop_Path(m_Path).string();
	std::string 拼接路径 = f_nodeCtx_相对路径补全(path);


	auto socket1 = f_get输入插座(1);
	auto socket2 = f_get输入插座(2);
	auto* InObjs = DEF_物体插座_1D数据(socket1, 0);
	
	bool 序列 = f_prop_Bool(m_序列文件);
	int32 帧 = 0;
	if (序列) {
		if (socket2->f_isLink()) {
			帧 = DEF_I32插座数据(socket2);
		}
		else {
			帧 = f_NodeCtx_get帧().当前帧;
		}
		m_更新方式 = E_节点更新方式::e_节点更新_逐帧;
	}
	else {
		m_更新方式 = E_节点更新方式::e_节点更新_被动;
	}
	
	bool 组 = bool(InObjs->count > 1);

	for (uint32 i = 0; i < InObjs->count; ++i) {
		std::u16string name;
		if (f_prop_Bool(m_使用物体名称)) {
			name = InObjs->ptr_userData[i]->m_Name;
		}
		else {
			name = f_prop_LineStr(m_文件名称);
			name += 组 ? f_str_string_to_u16(f_整数值转字符串(i)) : u"";
		}
		

		auto 路径 = f_缓存文件路径生成(m_Path, name, 序列, 帧, u".mesh_cache");


		FILE* F = fopen(路径.generic_string().c_str(), "wb");
		if (F) {
			Mat44f mm;
			Mat44f* matrix = nullptr;

			if (f_prop_Bool(m_应用变换)) {
				switch (f_prop_enum(m_中心变换方式)) {
					case 0: {
						mm = f_ob_构建XYZ变换矩阵euler(InObjs->ptr_userData[i]);
						break;
					}
					case 1: {
						mm = f_ob_构建XYZ变换矩阵euler(InObjs->ptr_userData[i]);
						mm = f_mat33_to_44(f_mat44_to_33(mm));
						break;
					}
					default:
						break;
				}
				matrix = &mm;
			}
			

			uint32 网格元素 = f_网格元素位域(m_元素);

			f_mesh_save(F, f_ob_getMesh(InObjs->ptr_userData[i], E_物体网格元素类型::e_MT_面), 网格元素, matrix, f_prop_Bool(m_压缩));

			fclose(F);
		}
	}
	return false;
}

void C_网格缓存写入节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件名称, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_使用物体名称, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_覆盖文件, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_序列文件, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_元素, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_应用变换, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_中心变换方式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_压缩, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_压缩等级, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_网格缓存写入节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_Path, 块);
	f_prop_Save(m_文件名称, 块);
	f_prop_Save(m_使用物体名称, 块);
	f_prop_Save(m_覆盖文件, 块);
	f_prop_Save(m_序列文件, 块);
	f_prop_Save(m_元素, 块);
	f_prop_Save(m_应用变换, 块);
	f_prop_Save(m_中心变换方式, 块);
	f_prop_Save(m_压缩, 块);
	f_prop_Save(m_压缩等级, 块);

	f_file_保存文件块(f, 文件块, 块);
}

S_物体* C_网格缓存写入节点::f_虚拟体() {
	return nullptr;
}

void C_网格缓存写入节点::f_删除()
{
}

void C_网格缓存写入节点::f_回收()
{
}

void C_网格缓存写入节点::f_Show(bool open)
{
}

C_节点基类* f_node_创建网格缓存写入节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_网格缓存写入节点(ctx);
}

C_节点基类* f_node_加载网格缓存写入节点(S_设备环境& ctx, FILE* f) {
	C_网格缓存写入节点* node = new C_网格缓存写入节点(ctx);
	return node;
}

void f_node_保存网格缓存写入节点(C_节点基类* n, FILE* f) {
	C_网格缓存写入节点* node = dynamic_cast<C_网格缓存写入节点*>(n);
}





C_读取网格缓存节点::C_读取网格缓存节点(S_设备环境& ctx) : C_节点基类(DEF_读取网格缓存节点) {
	f_setWName(u"读取网格缓存");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建I32插座_I(u"帧");
	DEF_创建物体_1D插座_O(u"物体");

	m_递归目录 = f_alloc_BoolProp(nullptr, u"序列文件");
	m_递归目录.m_私有 = true;

	m_所有文件 = f_alloc_BoolProp(nullptr, u"所有文件");
	m_所有文件.m_私有 = true;

	m_Path = f_alloc_PathProp(nullptr, u"文件路径");
	m_Path.m_私有 = true;

	m_文件名称 = f_alloc_LineStrProp(nullptr, u"文件名称");
	m_文件名称.m_私有 = true;

	m_序列文件 = f_alloc_BoolProp(nullptr, u"序列文件");
	m_序列文件.m_私有 = true;
	f_prop_Bool(m_序列文件) = false;

	m_循环区间 = f_alloc_UI32Prop(nullptr, u"序列文件", 0);
	m_循环区间.m_私有 = true;

	
	m_元素 = f_网格元素位域属性创建();
	m_过滤格式 = f_prop_创建外部模型格式属性数据();

	m_应用变换 = f_alloc_BoolProp(nullptr, u"应用变换");
	m_应用变换.m_私有 = true;
	f_prop_Bool(m_应用变换) = true;

	m_中心变换方式 = f_alloc_EnumProp(nullptr, {
		{u"保存偏移",	u""},
		{u"世界原点",	u""},
		{u"原物体",		u""},
		}, u"中心变换");
	m_中心变换方式.m_私有 = true;
	f_prop_enum(m_中心变换方式) = 0;


	m_填充多边形 = f_alloc_BoolProp(nullptr, u"序列文件");
	m_填充多边形.m_私有 = true;
	f_prop_Bool(m_填充多边形) = false;



	m_上一次加载路径 = std::filesystem::temp_directory_path().string();
	m_自定义更新方式 = true;
}

C_读取网格缓存节点::~C_读取网格缓存节点() {
	f_prop_Release(m_递归目录);
	f_prop_Release(m_Path);
	f_prop_Release(m_文件名称);
	f_prop_Release(m_序列文件);
	f_prop_Release(m_元素);
	f_prop_Release(m_过滤格式);
	f_prop_Release(m_应用变换);
	f_prop_Release(m_中心变换方式);
}

void C_读取网格缓存节点::f_加载网格(const std::filesystem::path& path) {

	auto socket1 = f_get输入插座(1);
	
	auto* InObjs = DEF_物体插座_1D数据(socket1, 0);
	


	auto* OutObjs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_node_创建模型物体组(OutObjs, InObjs->count, E_物体类型::t_网格物体, m_Ctx);


	for (uint32 i = 0; i < InObjs->count; ++i) {
		//auto 路径 = 拼接路径;

		uint32 循环区间 = f_prop_UI32(m_循环区间);
		if (循环区间) {
			循环区间 = i - ((i / 循环区间) * 循环区间);
		}
		else {
			循环区间 = i;
		}
		

		FILE* F = fopen(path.generic_string().c_str(), "rb");
		if (F) {
			uint32 网格元素 = f_网格元素位域(m_元素);

			f_mesh_load(F, f_ob_getMesh(OutObjs->ptr_userData[i], E_物体网格元素类型::e_MT_面), 网格元素);

			fclose(F);
		}

	}


}

bool C_读取网格缓存节点::f_update() {
	if (f_更新是否跳过()) return false;

	auto socket2 = f_get输入插座(2);
	int32 帧 = 0;
	
	bool 序列 = f_prop_Bool(m_序列文件);
	if (序列) {
		if (socket2->f_isLink()) {
			帧 = DEF_I32插座数据(socket2);
		}
		else {
			帧 = f_NodeCtx_get帧().当前帧;
		}
		m_更新方式 = E_节点更新方式::e_节点更新_逐帧;
	}
	else {
		m_更新方式 = E_节点更新方式::e_节点更新_被动;
	}


	auto path = f_prop_Path(m_Path);
	auto 拼接路径 = f_nodeCtx_相对路径补全(path);

	if (f_prop_Bool(m_所有文件)) {
		if (f_file_路径是否为目录(拼接路径) == false) return false;

		std::vector<std::string> 过滤文件 = {".fbx"};

		S_目录文件包 文件包;
		f_file_get目录下所有文件名(拼接路径.generic_string(), 文件包, 过滤文件);

		for (auto& e : 文件包.文件) {
			auto 路径 = f_缓存文件路径生成(m_Path, e, 序列, 0, u".mesh_cache");
			f_加载网格(路径);
		}
	}
	else {
		std::u16string name = f_prop_LineStr(m_文件名称);
		if (f_file_文件是否存在(拼接路径 / (name + u".mesh_cache")) == false) return false;

		
		auto 路径 = f_缓存文件路径生成(m_Path, name, 序列, 帧, u".mesh_cache");
		f_加载网格(路径);
	}
	

	return false;
}

void C_读取网格缓存节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_递归目录, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_所有文件, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件名称, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_序列文件, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_循环区间, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_元素, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_过滤格式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_应用变换, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_中心变换方式, 下一次读取数据指针);


			m_变换组.clear();
			下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, m_变换组, false);
		}
	}
	free(文件块.m_data);
}

void C_读取网格缓存节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_递归目录, 块);
	f_prop_Save(m_所有文件, 块);
	f_prop_Save(m_Path, 块);
	f_prop_Save(m_文件名称, 块);
	f_prop_Save(m_序列文件, 块);
	f_prop_Save(m_循环区间, 块);
	f_prop_Save(m_元素, 块);
	f_prop_Save(m_过滤格式, 块);
	f_prop_Save(m_应用变换, 块);
	f_prop_Save(m_中心变换方式, 块);


	auto* OutObjs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	m_变换组.clear();
	for (uint32 i = 0; i < OutObjs->count; ++i) {
		m_变换组.push_back(OutObjs->ptr_userData[i]->m_变换);
	}
	f_文件块_写序列数据块(块, m_变换组, false);


	f_file_保存文件块(f, 文件块, 块);
}

S_物体* C_读取网格缓存节点::f_虚拟体() {
	return nullptr;
}

void C_读取网格缓存节点::f_删除()
{
}

void C_读取网格缓存节点::f_回收()
{
}

void C_读取网格缓存节点::f_Show(bool open)
{
}

C_节点基类* f_node_创建读取网格缓存节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_读取网格缓存节点(ctx);
}

C_节点基类* f_node_加载读取网格缓存节点(S_设备环境& ctx, FILE* f) {
	C_读取网格缓存节点* node = new C_读取网格缓存节点(ctx);
	return node;
}

void f_node_保存读取网格缓存节点(C_节点基类* n, FILE* f) {
	C_读取网格缓存节点* node = dynamic_cast<C_读取网格缓存节点*>(n);
}











